home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / bit / src / forms / FORMS / input.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  11KB  |  395 lines

  1. /*
  2.  * input.c
  3.  *
  4.  * Forms Object class: INPUT
  5.  *
  6.  * Written by: Mark Overmars and Anthony Woodward
  7.  *
  8.  * Version 2.1 b
  9.  * Date: Sep 29, 1992
  10.  */
  11.  
  12. #include <malloc.h>
  13. #include <stdio.h>
  14. #include <strings.h>
  15. #include <stdlib.h>
  16. #include <sys/types.h>
  17. #include "gl/device.h"
  18. #include "forms.h"
  19.  
  20. /* Extra information need for input boxes. */
  21. typedef struct {
  22.    int    textcol;    /* text color */
  23.    int    curscol;    /* cursor color */
  24.    int    position;    /* cursor position */
  25.    int    beginrange;    /* start of the range */
  26.    int    endrange;    /* end of the range */
  27.    char *str;         /* the input text */
  28.    int size;        /* size of the string */
  29.    int changed;        /* whether the field has changed */
  30.    int always;        /* whether to return value always */
  31. } SPEC;
  32.  
  33. static void draw_input(FL_OBJECT *ob)
  34. {
  35.   int col,textcol,valign;
  36.   float xmargin, ymargin;
  37.   SPEC *sp = ((SPEC *)(ob->spec)); 
  38.   if (ob->focus) col = ob->col2; else col = ob->col1;
  39.   fl_drw_box(ob->boxtype,ob->x,ob->y,ob->w,ob->h,col,FL_INPUT_BW);
  40.   fl_drw_text_beside(ob->align,ob->x,ob->y,ob->w,ob->h,
  41.             ob->lcol,ob->lsize,ob->lstyle,ob->label);
  42.   if (ob->type == FL_MULTILINE_INPUT) valign = 1; else valign = 0;
  43.   if (ob->boxtype == FL_UP_BOX || ob->boxtype == FL_DOWN_BOX ||
  44.     ob->boxtype == FL_ROUNDED_BOX || ob->boxtype == FL_RSHADOW_BOX ||
  45.     ob->boxtype == FL_RFLAT_BOX)
  46.     { xmargin = 2.0*FL_INPUT_BW; ymargin = 1.5*FL_INPUT_BW;}
  47.   else
  48.     { xmargin = 1.0*FL_INPUT_BW; ymargin = 0.5*FL_INPUT_BW;}
  49.   if (ob->type == FL_SECRET_INPUT) textcol = col; else textcol = sp->textcol;
  50.   fl_drw_string(-1,valign,            /* Align left centered. */
  51.         ob->x+xmargin,            /* Bounding box */
  52.         ob->y+ymargin,
  53.                 ob->w-2.0*xmargin,
  54.         ob->h-2.0*ymargin,
  55.         TRUE,                /* Do clipping */
  56.         col,textcol,sp->curscol,    /* Colors */
  57.         ob->lsize,ob->lstyle,        /* Size and style */
  58.         sp->position,            /* Cursor position */
  59.         sp->beginrange,sp->endrange,    /* Selection range */
  60.         sp->str);
  61. }
  62.  
  63. static int handle_select(float mx, float my, FL_OBJECT *ob, int mouse)
  64. /* figures out selection region of mouse. Returns whether anything changed */
  65. {
  66.   SPEC *sp = ((SPEC *)(ob->spec));
  67.   int thepos;
  68.   int oldpos = sp->position;
  69.   int oldbeg = sp->beginrange;
  70.   int oldend = sp->endrange;
  71.   int valign;
  72.   float xmargin,ymargin;
  73.    
  74.   if (ob->type == FL_HIDDEN_INPUT || ob->type == FL_SECRET_INPUT) return 0;
  75.   /* Compute the mouse position in the string */
  76.   if (ob->type == FL_MULTILINE_INPUT) valign = 1; else valign = 0;
  77.   if (ob->boxtype == FL_UP_BOX || ob->boxtype == FL_DOWN_BOX ||
  78.     ob->boxtype == FL_ROUNDED_BOX || ob->boxtype == FL_RSHADOW_BOX ||
  79.     ob->boxtype == FL_RFLAT_BOX)
  80.     { xmargin = 2.0*FL_INPUT_BW; ymargin = 1.5*FL_INPUT_BW;}
  81.   else
  82.     { xmargin = 1.0*FL_INPUT_BW; ymargin = 0.5*FL_INPUT_BW;}
  83.   thepos = fl_get_pos_in_string(-1,valign,
  84.                 ob->x+xmargin,
  85.                 ob->y+ymargin,
  86.                         ob->w-2.0*xmargin,
  87.                 ob->h-2.0*ymargin,
  88.                 ob->lsize, ob->lstyle,
  89.                 mx,my,sp->str);
  90.   /* Adapt the range */
  91.   if (mouse)
  92.   {
  93.     if (thepos < sp->position)
  94.       { sp->endrange = sp->position; sp->beginrange = thepos;}
  95.     else 
  96.       { sp->beginrange = sp->position; sp->endrange = thepos;}
  97.   }
  98.   else
  99.     { sp->position = sp->beginrange = thepos; sp->endrange = -1; }
  100.   if (sp->beginrange == sp->endrange) sp->endrange = -1;
  101.   return (oldpos != sp->position || oldbeg != sp->beginrange ||
  102.         oldend != sp->endrange);
  103. }
  104.  
  105. static void delete_piece(FL_OBJECT *ob, int beginrange, int endrange)
  106. /* Removes a piece of the string */
  107. {
  108.   SPEC *sp = ((SPEC *)(ob->spec));
  109.   int i = 0;
  110.   do {
  111.     i++;
  112.     sp->str[beginrange+i-1] = sp->str[endrange+i];
  113.   } while (sp->str[endrange+i] != '\0');
  114.   sp->position = beginrange;
  115. }
  116.  
  117. static float get_substring_width(FL_OBJECT *ob, int startpos, int endpos)
  118. /* Returns the width of the substring of the input field */
  119. {
  120.   SPEC *sp = ((SPEC *)(ob->spec));
  121.   char tmpch = sp->str[endpos];        /* Save end position */
  122.   float wid;                /* The required width */
  123.   sp->str[endpos] = '\0';
  124.   wid = fl_get_string_width(ob->lsize,ob->lstyle,&(sp->str[startpos]));
  125.   sp->str[endpos] = tmpch;        /* Restore end position */
  126.   return wid;
  127. }
  128.  
  129. static int handle_key(FL_OBJECT *ob, char key)
  130. /* Handles a key press, returns whether something has changed */
  131. {
  132.   int i, ret = 1;
  133.   SPEC *sp = ((SPEC *)(ob->spec));
  134.   char *ptr;            /* pointer to string */
  135.   char *old;            /* store previous value */
  136.   int oldpos;            /* old position */
  137.   int slen;            /* length of the string */
  138.   int startpos;            /* position of start of current line */
  139.   float wid,oldwid,tt;        /* width of substring */
  140.   int ready;
  141.  
  142.   /* Save old situation */
  143.   if (ob->type == FL_FLOAT_INPUT || ob->type == FL_INT_INPUT)
  144.   {
  145.     oldpos = sp->position;
  146.     old = (char *) fl_malloc(sp->size+1);
  147.     strcpy(old,sp->str);
  148.   }
  149.  
  150.   /* Extend field size if required */
  151.   slen = strlen(sp->str);
  152.   if (sp->size == slen+1)
  153.   {
  154.     sp->size += 8;
  155.     sp->str = (char *) realloc(sp->str,sp->size);
  156.   }
  157.  
  158.   if (ob->type == FL_MULTILINE_INPUT && key == 13) key = 10;
  159.   /* Compute starting position of current line */
  160.   startpos = sp->position;
  161.   while (startpos > 0 && sp->str[startpos-1] != 10) startpos--;
  162.   switch (key)
  163.   {
  164.     case  1:  /* Left key */
  165.       if (getbutton(LEFTSHIFTKEY) || getbutton(RIGHTSHIFTKEY))
  166.         while (sp->position > 0 && sp->str[sp->position-1] != 10)
  167.       sp->position--;
  168.       else if (sp->position >0)
  169.     sp->position--;
  170.       ret = 0;
  171.       break;
  172.     case  2:  /* Right key */
  173.       if (getbutton(LEFTSHIFTKEY) || getbutton(RIGHTSHIFTKEY))
  174.         while (sp->position < slen && sp->str[sp->position] != 10)
  175.       sp->position++;
  176.       else if (sp->position < slen)
  177.     sp->position++;
  178.       ret = 0;
  179.       break;
  180.     case  3:  /* Up key */
  181.       if (getbutton(LEFTSHIFTKEY) || getbutton(RIGHTSHIFTKEY))
  182.         sp->position = 0;
  183.       else if (startpos != 0)
  184.       {
  185.     wid = get_substring_width(ob,startpos,sp->position);
  186.     i = startpos -1;
  187.         while (i > 0 && sp->str[i-1] != 10) i--;
  188.     oldwid = 0.0;
  189.     sp->position = i;
  190.     ready = (sp->str[sp->position] == 10);
  191.     while (!ready)
  192.     {
  193.       tt = get_substring_width(ob,i,sp->position+1);
  194.       ready = (oldwid+tt)/2.0 >= wid;
  195.       oldwid = tt;
  196.       if (!ready) sp->position++;
  197.       if (sp->str[sp->position] == 10) ready = TRUE;
  198.     }
  199.       }
  200.       ret = 0;
  201.       break;
  202.     case  4:  /* Down key */
  203.       if (getbutton(LEFTSHIFTKEY) || getbutton(RIGHTSHIFTKEY))
  204.         sp->position = slen;
  205.       else
  206.       {
  207.     wid = get_substring_width(ob,startpos,sp->position);
  208.     i = sp->position+1;
  209.         while (i < slen && sp->str[i-1] != 10) i++;
  210.     if (i < slen)
  211.     {
  212.       oldwid = 0.0;
  213.       sp->position = i;
  214.       ready = (sp->position == slen || sp->str[sp->position] == 10);
  215.       while (!ready)
  216.       {
  217.         tt = get_substring_width(ob,i,sp->position+1);
  218.         ready = (oldwid+tt)/2.0 >= wid;
  219.         oldwid = tt;
  220.         if (!ready) sp->position++;
  221.         if (sp->position == slen || sp->str[sp->position] == 10)
  222.           ready = TRUE;
  223.       }
  224.     }
  225.       }
  226.       ret = 0;
  227.       break;
  228.     case  0x7f:  /* Delete key*/
  229.       if (sp->endrange >= 0)
  230.     delete_piece(ob,sp->beginrange,sp->endrange-1);
  231.       else if (sp->position < slen)
  232.     delete_piece(ob,sp->position,sp->position);
  233.       else
  234.     ret = 0;
  235.       break;
  236.     case  8:  /* Backspace */
  237.       if (sp->endrange >= 0)
  238.     delete_piece(ob,sp->beginrange,sp->endrange-1);
  239.       else if (sp->position >0)
  240.     delete_piece(ob,sp->position-1,sp->position-1);
  241.       else
  242.     ret = 0;
  243.       break;
  244.     case 27:  /* Esc key */
  245.       if (slen>0)
  246.     delete_piece(ob,0,slen-1);
  247.       else
  248.     ret = 0;
  249.       break;
  250.     default:
  251.       if ( key >= 32 || key == 10) /* Normal keys  or NL*/
  252.       {
  253.     if (sp->endrange >= 0)
  254.       delete_piece(ob,sp->beginrange,sp->endrange-1);
  255.     /* Add the character */
  256.     for (i=slen+1; i>sp->position; i--)
  257.       sp->str[i] = sp->str[i-1];
  258.     sp->str[sp->position] = key;
  259.     sp->position++;
  260.       }
  261.       else
  262.     return 0;
  263.   }
  264.   sp->endrange = -1;
  265.  
  266.   /* Check whether change was correct. */
  267.   if (ob->type == FL_FLOAT_INPUT || ob->type == FL_INT_INPUT)
  268.   {
  269.     if (ob->type == FL_FLOAT_INPUT)
  270.       strtod(sp->str,&ptr);
  271.     else
  272.       strtol(sp->str,&ptr,10);
  273.     slen = strlen(sp->str);
  274.     if (*ptr != '\0' && strcmp(sp->str,"-") != 0 &&
  275.         (sp->str[slen-1] != '-' || sp->str[slen-2] != 'e'))
  276.       { strcpy(sp->str,old); sp->position = oldpos; ringbell(); ret = 0;}
  277.     free(old);
  278.   }
  279.   fl_redraw_object(ob);
  280.   return ret;
  281. }
  282.  
  283. static int handle_input(FL_OBJECT *ob,int event,float mx,float my,char key)
  284. /* Handles an event */
  285. {
  286.   SPEC *sp = ((SPEC *)(ob->spec));
  287.   switch (event)
  288.   {
  289.     case FL_DRAW:
  290.     if (ob->type != FL_HIDDEN_INPUT) draw_input(ob);
  291.     return 0;
  292.     case FL_FOCUS:
  293.     sp->position = strlen(sp->str);
  294.         sp->changed = FALSE;
  295.     fl_redraw_object(ob);
  296.     return 0;
  297.     case FL_UNFOCUS:
  298.     sp->position = -1;
  299.     sp->endrange = -1;
  300.     fl_redraw_object(ob);
  301.     return sp->changed;
  302.     case FL_MOUSE:
  303.     if (handle_select(mx,my,ob,TRUE)) fl_redraw_object(ob);
  304.     return 0;
  305.     case FL_PUSH:
  306.     if (handle_select(mx,my,ob,FALSE)) fl_redraw_object(ob);
  307.     return 0;
  308.     case FL_KEYBOARD:
  309.     if (handle_key(ob,key))
  310.         {
  311.       sp->changed = TRUE;
  312.       return (sp->always);
  313.         }
  314.     else
  315.       return 0;
  316.     case FL_FREEMEM:
  317.     free(((SPEC *)(ob->spec))->str);
  318.     free(ob->spec);
  319.     return 0;
  320.   }
  321.   return 0;
  322. }
  323.  
  324. /*------------------------------*/
  325.  
  326. FL_OBJECT *fl_create_input(int type,float x,float y,float w,float h,const
  327. char *label)
  328. /* creates an object */
  329. {
  330.   FL_OBJECT *ob;
  331.   ob = fl_make_object(FL_INPUT,type,x,y,w,h,label,handle_input);
  332.   ob->boxtype = FL_INPUT_BOXTYPE;
  333.   ob->col1 = FL_INPUT_COL1;
  334.   ob->col2 = FL_INPUT_COL2;
  335.   ob->align = FL_INPUT_ALIGN;
  336.   ob->lcol = FL_INPUT_LCOL;
  337.   ob->input = 1;
  338.   ob->wantall = (ob->type == FL_MULTILINE_INPUT);
  339.  
  340.   ob->spec = (int *) fl_malloc(sizeof(SPEC));
  341.   ((SPEC *)(ob->spec))->textcol  = FL_INPUT_TCOL;
  342.   ((SPEC *)(ob->spec))->curscol  = FL_INPUT_CCOL;
  343.   ((SPEC *)(ob->spec))->position = -1;
  344.   ((SPEC *)(ob->spec))->endrange = -1;
  345.   ((SPEC *)(ob->spec))->size = 8;
  346.   ((SPEC *)(ob->spec))->str = (char *) fl_malloc(8);
  347.   ((SPEC *)(ob->spec))->str[0]     = '\0';
  348.   ((SPEC *)(ob->spec))->always = 0;
  349.  
  350.   return ob;
  351. }
  352.  
  353. FL_OBJECT *fl_add_input(int type, float x, float y, float w, float h, const
  354. char *label)
  355. /* Adds an object */
  356. {
  357.   FL_OBJECT *ob;
  358.   ob = fl_create_input(type,x,y,w,h,label);
  359.   fl_add_object(fl_current_form,ob);
  360.   return ob;
  361. }
  362.  
  363. void fl_set_input(FL_OBJECT *ob, const char *str)
  364. /* Sets the particular input string. */
  365. {
  366.   SPEC *sp = ((SPEC *)(ob->spec));
  367.   if (sp->size < strlen(str)+1)
  368.   {
  369.     sp->size = strlen(str)+1;
  370.     sp->str = (char *) realloc(sp->str,sp->size);
  371.   }
  372.   strcpy(sp->str,str);
  373.   if (sp->position != -1) sp->position = strlen(sp->str);
  374.   sp->endrange = -1;
  375.   fl_redraw_object(ob);
  376. }
  377.  
  378. void fl_set_input_color(FL_OBJECT *ob, int textcol, int curscol)
  379. /* Sets the color of the input string. */
  380. {
  381.   ((SPEC *)(ob->spec))->textcol  = textcol;
  382.   ((SPEC *)(ob->spec))->curscol  = curscol;
  383.   fl_redraw_object(ob);
  384. }
  385.  
  386. const char *fl_get_input(FL_OBJECT *ob)
  387. /* returns a pointer to the text string */
  388.   { return ((SPEC *)(ob->spec))->str; }
  389.  
  390. void fl_set_input_return(FL_OBJECT *ob, int value)
  391. /* Sets whether to return value all the time or only when pressing return */
  392. {
  393.   ((SPEC *)(ob->spec))->always = value;
  394. }
  395.